import { each, map, findIndex, trim } from "lodash";
import React, { useEffect, useState } from "react";
import Modal from "antd/lib/modal";
import Form from "antd/lib/form";
import DatePicker from "antd/lib/date-picker";
import { Radio, Button, Space } from "antd";
import * as Grid from "antd/lib/grid";
import { RendererPropTypes } from "@/visualizations/prop-types";
import HtmlContent from "@/components/HtmlContent";
import { Select, Input, Checkbox, InputNumber, TextArea } from "@/components/visualizations/editor";
import { getUrlParameterValue, getUrlParameters } from "@/lib/DateRangeParameter";
import { currentUser } from "@/../../../../client/app/services/auth";
import notification from "@/../../../../client/app/services/notification";

import SaveOutlined from "@ant-design/icons/SaveOutlined";
import DeleteOutlined from "@ant-design/icons/DeleteOutlined";
import LeftOutlined from "@ant-design/icons/LeftOutlined";
import RightOutlined from "@ant-design/icons/RightOutlined";

import { axios } from "@/services/axios";
import "./renderer.less";

function DoDefaultValue(originstr) {
  if (!originstr) return originstr;

  let mats = /\{\{(.|\n)*?\}\}/m.exec(originstr);
  if (!mats) return originstr;
  if (!(mats instanceof Array)) return originstr;

  let oldstr = mats[0].toString();
  let functions;
  try {
    let objstr = oldstr.substring(1, oldstr.length-1)
    functions = JSON.parse(objstr);
  } catch(e) {
    return originstr;
  }

  if (functions.hasOwnProperty("parameter")) {
    let parameterValue = getUrlParameterValue(functions.parameter)
    return parameterValue;
  }

  if (functions.hasOwnProperty("cookie")) {
    let cookieStr = "";
    if (!!functions.cookie && showPortal) cookieStr = localStorage.getItem(functions.cookie);
    
    return cookieStr;
  }

  if (functions.session.indexOf("currentUser_") === 0) {
    const userProperty = functions.session.substring(12);
    if (currentUser.hasOwnProperty(userProperty)) {
      sessionStr = currentUser[userProperty];   
      return sessionStr;     
    }
  }
  return originstr;
}

function RenderNodeEnum(col, defaultValue) {
  const showPortal = window.location.search.includes("show_portal") && localStorage.getItem('colorstyle_mode');
  const cssStyle = {
    "--style-color": localStorage.getItem("colorstyle_color"),
  };
  const cssStyles = {
    "--style-color": localStorage.getItem("colorstyle_color"),
    width: '100%',
    minWidth: '100px',
  };
  const cssStylesEdit = {
    width: '100%',
    minWidth: '100px',
  };

  let nodeContent;
  switch(col.selectDisplay) {
    case 'option':
      nodeContent = (
        <Grid.Col span={col.contentCols || 9}>
        <Radio.Group size="large"
          key={col.name}
          defaultValue={defaultValue}
          disabled={defaultValue && !!col.is_disable}
        >
          <Space direction="vertical">
          {col.enumOptions && map(col.enumOptions.split("\n"), opt => (
            <Radio value={opt}
              style={showPortal ? {backgroundColor: "#00000000", color: localStorage.getItem("colorstyle_color"), height: '35px'} : {height: '35px'}}
            >
              {String(opt)}
            </Radio>
          ))}
          </Space>
        </Radio.Group>
        </Grid.Col>
      );
      break;
    case 'button':
      nodeContent = (
        <Grid.Col span={col.contentCols || 9}>
        <Radio.Group
          key={col.name}
          buttonStyle="outline"
          defaultValue={defaultValue}
          disabled={defaultValue && !!col.is_disable}
        >
          {col.enumOptions && map(col.enumOptions.split("\n"), opt => (
            <Radio.Button value={opt}
              style={showPortal ? {backgroundColor: "#00000000", color: localStorage.getItem("colorstyle_color"), height: '35px'} : {height: '35px'}}
            >
              {String(opt)}
            </Radio.Button>
          ))}
        </Radio.Group>
        </Grid.Col>
      );
      break;
    default:
      nodeContent = (
        <Grid.Col span={col.contentCols || 9}>
        <Select
          key={col.name}
          placeholder={!!col.is_notnull && "必填项"}
          className={showPortal ? "parameter-select" : null}
          style={showPortal ? cssStyles : cssStylesEdit}
          defaultValue={defaultValue}
          options={col.enumOptions && map(col.enumOptions.split("\n"), opt => ({ label: String(opt), value: opt }))}
          showSearch
          optionFilterProp="label"
          allowClear   
          disabled={defaultValue && !!col.is_disable}
        />
        </Grid.Col>
      );
    }
  return nodeContent;
}

function RenderNodeEnums(items, col, defaultValue) {
  const showPortal = window.location.search.includes("show_portal") && localStorage.getItem('colorstyle_mode');
  const cssStyle = {
    "--style-color": localStorage.getItem("colorstyle_color"),
  };
  const cssStyles = {
    "--style-color": localStorage.getItem("colorstyle_color"),
    width: '100%',
    minWidth: '100px',
  };
  const cssStylesEdit = {
    width: '100%',
    minWidth: '100px',
  };

  if (items.length === 0) return null;

  let nodeContent;
  switch(col.selectDisplay) {
    case 'option':
      nodeContent = (
        <Grid.Col span={col.contentCols || 9}>
        <Radio.Group size="large"
          key={col.name}
          defaultValue={defaultValue}
          disabled={defaultValue && !!col.is_disable}
        >
          <Space direction="vertical">
          {map(items, opt => (
            <Radio value={opt.value}
              style={showPortal ? {backgroundColor: "#00000000", color: localStorage.getItem("colorstyle_color"), height: '35px'} : {height: '35px'}}
            >
              {opt.label}
            </Radio>
          ))}
          </Space>
        </Radio.Group>
        </Grid.Col>
      );
      break;
    case 'button':
      nodeContent = (
        <Grid.Col span={col.contentCols || 9}>
        <Radio.Group
          key={col.name}
          buttonStyle="outline"
          defaultValue={defaultValue}
          disabled={defaultValue && !!col.is_disable}
        >
          {map(items, opt => (
            <Radio.Button value={opt.value}
              style={showPortal ? {backgroundColor: "#00000000", color: localStorage.getItem("colorstyle_color"), height: '35px'} : {height: '35px'}}
            >
              {opt.label}
            </Radio.Button>
          ))}
        </Radio.Group>
        </Grid.Col>
      );
      break;
    default:
      nodeContent = (
        <Grid.Col span={col.contentCols || 9}>
        <Select
          key={col.name}
          placeholder={!!col.is_notnull && "必填项"}
          className={showPortal ? "parameter-select" : null}
          style={showPortal ? cssStyles : cssStylesEdit}
          defaultValue={defaultValue}
          options={items}
          showSearch
          optionFilterProp="label"
          allowClear   
          disabled={defaultValue && !!col.is_disable}
        />
        </Grid.Col>
      );
    }
  return nodeContent;
}

function RenderNodeQuery(items, col, defaultValue) {
  const showPortal = window.location.search.includes("show_portal") && localStorage.getItem('colorstyle_mode');
  const cssStyle = {
    "--style-color": localStorage.getItem("colorstyle_color"),
  };
  const cssStyles = {
    "--style-color": localStorage.getItem("colorstyle_color"),
    width: '100%',
    minWidth: '100px',
  };
  const cssStylesEdit = {
    width: '100%',
    minWidth: '100px',
  };

  if (items.length === 0) return null;

  let nodeContent;
  switch(col.selectDisplay) {
    case 'option':
      nodeContent = (
        <Grid.Col span={col.contentCols || 9}>
        <Radio.Group size="large"
          key={col.name}
          defaultValue={defaultValue}
          disabled={defaultValue && !!col.is_disable}
        >
          <Space direction="vertical">
          {map(items, opt => (
            <Radio value={opt.value}
              style={showPortal ? {backgroundColor: "#00000000", color: localStorage.getItem("colorstyle_color"), height: '35px'} : {height: '35px'}}
            >
              {opt.name}
            </Radio>
          ))}
          </Space>
        </Radio.Group>
        </Grid.Col>
      );
      break;
    case 'button':
      nodeContent = (
        <Grid.Col span={col.contentCols || 9}>
        <Radio.Group
          key={col.name}
          buttonStyle="outline"
          defaultValue={defaultValue}
          disabled={defaultValue && !!col.is_disable}
        >
          {map(items, opt => (
            <Radio.Button value={opt.value}
              style={showPortal ? {backgroundColor: "#00000000", color: localStorage.getItem("colorstyle_color"), height: '35px'} : {height: '35px'}}
            >
              {opt.name}
            </Radio.Button>
          ))}
        </Radio.Group>
        </Grid.Col>
      );
      break;
    default:
      nodeContent = (
        <Grid.Col span={col.contentCols || 9}>
        <Select
          key={col.name}
          placeholder={!!col.is_notnull && "必填项"}
          className={showPortal ? "parameter-select" : null}
          style={showPortal ? cssStyles : cssStylesEdit}
          defaultValue={defaultValue}
          options={map(items, opt => ({ label: opt.name, value: opt.value }))}
          showSearch
          optionFilterProp="label"
          allowClear   
          disabled={defaultValue && !!col.is_disable}
        />
        </Grid.Col>
      );
    }
  return nodeContent;
}

function RenderNode({queryId, col, row=[]}) {
  const [enumsItems, setEnumsItems] = useState([]);
  const [queryItems, setQueryItems] = useState([]);

  const showPortal = window.location.search.includes("show_portal") && localStorage.getItem('colorstyle_mode');
  const cssStyle = {
    "--style-color": localStorage.getItem("colorstyle_color"),
  };
  const cssStyles = {
    "--style-color": localStorage.getItem("colorstyle_color"),
    width: '100%',
    minWidth: '100px',
  };
  const cssStylesEdit = {
    width: '100%',
    minWidth: '100px',
  };

  const handleCoderChange = (value, coderRule) => {
    if (!coderRule) return;
    if (!new RegExp(coderRule).test(value)) {
      notification.error("不符合编码规则！");
    }
  }

  useEffect(() => {
    if (col.displayAs === 'enums' && col.enums_code) {
      axios.get('api/enums/items/' + col.enums_code).then((items) => {
        setEnumsItems(items);
      })
    }
    if (col.displayAs === 'query' && queryId && col.query_id) {
      axios.get('api/queries/' + queryId + '/dropdowns/' + col.query_id).then((items) => {
        setQueryItems(items);
      })
    }
  }, [col.displayAs]);

  if (!col.visible) return null;
  
  let nodeTitle, nodeContent, nodeDescription;
  //处理标题
  nodeTitle = (
    <Grid.Col span={col.titleCols || 3} style={{textAlign: col.alignContent || 'right'}}>
      {col.displayAs !== 'hidden' && (
        <div>
        {!!col.is_notnull && (<i className="fa fa-star" style={{display: "inline"}}/>)}
        <HtmlContent 
          style={showPortal ? {backgroundColor: "#00000000", color: localStorage.getItem("colorstyle_color"), display: "inline"} : {display: "inline"}}
        >
          {col.title}
        </HtmlContent>
        </div>
      )}
    </Grid.Col>
  )
  //处理描述
  nodeDescription = col.description && (
    <Grid.Col span={col.descriptionCols}>
      <label style={showPortal ? {backgroundColor: "#00000000", color: localStorage.getItem("colorstyle_color")} : null}>
        {col.description}
      </label>
    </Grid.Col>
  )
  
  const initValue = DoDefaultValue(col.defaultValue);
  const defaultValue = row[col.name] || initValue;
  let initValue0;  

  switch(col.displayAs) {
  case 'number':
    nodeContent = (
      <Grid.Col span={col.contentCols || 9}>
      <InputNumber
        key={col.name}
        placeholder={!!col.is_notnull && "必填项"}
        className={showPortal ? "parameter-inputnumber" : null}
        style={showPortal ? {backgroundColor: "#00000000", color: localStorage.getItem("colorstyle_color")} : null}
        min={col.minValue}
        max={col.maxValue}
        defaultValue={defaultValue}
        precision={col.decimal}
        step="1"
        disabled={defaultValue && !!col.is_disable}
      />
      </Grid.Col>
    );
    break;
  case 'boolean':
    nodeContent = (
      <Grid.Col span={col.contentCols || 9}>
      <Checkbox
        key={col.name}
        className={showPortal ? "parameter-checkbox" : null}
        style={showPortal ? cssStyle : null}
        defaultChecked={row[col.name] || col.defaultChecked}
        disabled={!!col.is_disable}
      />
      </Grid.Col>
    );
    break;
  case 'enum':
    initValue0 = !!col.is_notnull && col.enumOptions && col.enumOptions.split("\n")[0];
    nodeContent = RenderNodeEnum(col, defaultValue || initValue0);
    break;
  case 'enums':
    initValue0 = !!col.is_notnull && enumsItems.length>0 && enumsItems[0].value;
    nodeContent = RenderNodeEnums(enumsItems, col, defaultValue || initValue0);
    break;
  case 'query':
    initValue0 = !!col.is_notnull && queryItems.length>0 && queryItems[0].value;
    nodeContent = RenderNodeQuery(queryItems, col, defaultValue || initValue0);
    break;
  case 'date':
    nodeContent = (
      <Grid.Col span={col.contentCols || 9}>
      <DatePicker
        key={col.name}
        placeholder={!!col.is_notnull && "必填项"}
        className={showPortal ? "parameter-date" : null}
        style={showPortal ? cssStyle : null}
        defaultValue={defaultValue}
        format="YYYY-MM-DD"
        disabled={defaultValue && !!col.is_disable}
      />
      </Grid.Col>
    );
    break;
  case 'datetime':
    nodeContent = (
      <Grid.Col span={col.contentCols || 9}>
      <DatePicker
        key={col.name}
        placeholder={!!col.is_notnull && "必填项"}
        className={showPortal ? "parameter-date" : null}
        style={showPortal ? cssStyle : null}
        defaultValue={defaultValue}
        format="YYYY-MM-DD HH:mm"
        disabled={defaultValue && !!col.is_disable}
        showTime
      />
      </Grid.Col>
    );
    break;
  case 'hidden':
    nodeContent = (
      <Grid.Col span={col.contentCols || 9}>
      <Input
        type='hidden'
        key={col.name}
        className={showPortal ? "parameter-input" : null}
        style={showPortal ? cssStyle : null}
        defaultValue={defaultValue}
      />
      </Grid.Col>
    );
    break;
  case 'coder':
    nodeContent = (
      <Grid.Col span={col.contentCols || 9}>
      <Input
        key={col.name}
        placeholder={!!col.is_notnull && "必填项"}
        className={showPortal ? "parameter-input" : null}
        style={showPortal ? {backgroundColor: "#00000000", color: localStorage.getItem("colorstyle_color")} : null}
        defaultValue={defaultValue}
        onBlur={e => handleCoderChange(e.target.value, col.coderRule)}
      />
      </Grid.Col>
    );
    break;
  default:
    nodeContent = !!col.is_textarea ? (
      <Grid.Col span={col.contentCols || 9}>
      <TextArea
        key={col.name}
        placeholder={!!col.is_notnull && "必填项"}
        className={showPortal ? "parameter-input" : null}
        style={showPortal ? {backgroundColor: "#00000000", color: localStorage.getItem("colorstyle_color")} : null}
        defaultValue={defaultValue}
        rows="3"
      />
      </Grid.Col>
    ) : (
      <Grid.Col span={col.contentCols || 9}>
      <Input
        key={col.name}
        placeholder={!!col.is_notnull && "必填项"}
        className={showPortal ? "parameter-input" : null}
        style={showPortal ? {backgroundColor: "#00000000", color: localStorage.getItem("colorstyle_color")} : null}
        defaultValue={defaultValue}
      />
      </Grid.Col>
    );
  }  

  return (
    <React.Fragment>
    {nodeTitle}
    {!!row[col.name] ? (
        <Form.Item name={col.name} noStyle={true}>
        {nodeContent}
        </Form.Item>
      ) : (
        <Form.Item name={col.name} noStyle={true}
          initialValue={initValue || initValue0}
        >
        {nodeContent}
        </Form.Item>
      )
    }
    {nodeDescription}
    </React.Fragment>
  );
}

function getColumn(options, axis="x") {
  var result = 'id';
  each(options.columnMapping, (type, column) => {
    if (type === axis) {
      result = column;
      return false;
    }
  });          
  return result;
}

export default function Renderer({ data, options, queryId }) {
  const x = getColumn(options);
  const xValue = getUrlParameterValue(x);
  const [rowIndex, setRowIndex] = useState(!!xValue ? findIndex(data.rows, r => r[x].toString() === xValue) : -1);
  const [saveInProgress, setSaveInProgress] = useState(false);
  const [form] = Form.useForm();
  const tableName = DoDefaultValue(options.tablename);

  const turnLastPage = () => {
    form.resetFields();
    setRowIndex(rowIndex - 1);
  };

  const turnNextPage = () => {
    form.resetFields();
    setRowIndex(rowIndex + 1);
  };

  const onDelete = () => {
    const doDelete = () => {
      const url = `api/crud/${queryId}/t/${tableName}/i/${data.rows[rowIndex][x]}/k/${x}`

      setSaveInProgress(true);
      axios.delete(url).then(w => {
        if (w===true) {
          notification.success("删除成功！");
          form.resetFields();
          if (rowIndex>(data.rows.length-1)) setRowIndex(0);
        } else { 
          Modal.error({
            title: "删除失败",
            content: w,
          });
        }
        setSaveInProgress(false);
      }).catch(error => {
        setSaveInProgress(false);
      });  
    }

    if (!!options.is_deletemute) {
      doDelete();
    } else {
      Modal.confirm({
        title: "删除记录",
        content: "确定要删除该记录吗？",
        cancelText: "取消",
        okText: "删除",
        okType: "danger",
        onOk: () => doDelete(),
        maskClosable: true,
        autoFocusButton: null,
      });  
    } 
  };

  const onFinish = (values) => {
    var nullTitle = '';
    map(options.columns, col=> {
      if (!!col.visible && !!col.is_notnull) {
        if (data.rows.length === 0 || rowIndex<0) {
          if (!(col.name in values) || !values[col.name] || trim(values[col.name])==='') {
            nullTitle = nullTitle + col.title + '不能为空！\n';
          }
        } else {
          if ((col.name in values) && values[col.name] !== undefined && trim(values[col.name])==='') {
            nullTitle = nullTitle + col.title + '不能为空！\n';
          }
        } 
      }
      if (!!col.visible && col.displayAs === 'coder' && !!col.coderRule) {
        if ((col.name in values) && values[col.name] !== undefined && !new RegExp(col.coderRule).test(values[col.name])) {
          nullTitle = nullTitle + col.title + "不符合编码规则！\n";
        }    
      }
    });

    if (nullTitle !== '') {
      Modal.error({
        title: "保存检查",
        content: nullTitle,
      }); 
      return; 
    }

    var url = data.rows.length>=0 && rowIndex>=0 ? `api/crud/${queryId}/t/${tableName}/i/${data.rows[rowIndex][x]}/k/${x}` : `api/crud/${queryId}/t/${tableName}/i/0/k/${x}`;

    //勾选提交
    const selectedRowKeys = localStorage.getItem("selectedRowKeys");
    if (!!selectedRowKeys) {
      url = `api/tablecheckbox/${queryId}/t/${tableName}/i/0/k/${x}`;
      values.selectedRowKeys = selectedRowKeys.split(',');
      sessionStorage.removeItem("selectedRowKeys");
    }

    setSaveInProgress(true);
    axios.post(url, values).then(w => {
      if (w===true) {
        notification.success("保存成功！");
      } else { 
        Modal.error({
          title: "保存失败",
          content: w,
        });
      }
      setSaveInProgress(false);
    }).catch(error => {
      setSaveInProgress(false);
    });
  };
  
  return (
    <div className="crud_div" style={{display: "inline-block", marginLeft: '10px'}}>
      <Form key={'form_' + queryId} layout="horizontal" preserve={false} onFinish={onFinish} form={form} >
      <Grid.Row gutter={[16, 24]} type="flex" align="middle">
        <Grid.Col span='24'>
          <Button htmlType="submit" disabled={saveInProgress}><SaveOutlined />保存</Button>
          {data.rows.length>0 && rowIndex>=0 && !!options.is_delete && (
            <Button onClick={onDelete} disabled={saveInProgress}><DeleteOutlined />删除</Button>
          )}
          {data.rows.length>=2 && rowIndex>=0 && !!options.is_turn && (
            <Button onClick={turnLastPage} disabled={saveInProgress || rowIndex === 0} ><LeftOutlined />上页</Button>
          )}
          {data.rows.length>=2 && rowIndex>=0 && !!options.is_turn && (
            <Button onClick={turnNextPage} disabled={saveInProgress || rowIndex === data.rows.length-1} ><RightOutlined />下页</Button>
          )}
        </Grid.Col>
      </Grid.Row>
      <Grid.Row gutter={[16, 24]} type="flex" align="middle">
        {map(options.columns, col=> (
          <RenderNode 
            queryId={queryId} 
            col={col} 
            row={data.rows.length>0 && rowIndex>=0 && data.rows[rowIndex]}
          />
        ))}
      </Grid.Row>
      </Form>
    </div>
  );
}

Renderer.propTypes = RendererPropTypes;
